#pragma once

#include "state.h"
#include <assert.h>

#define PROPERTY_GET(type, name) type Get##name(void) { return m_p##name; }
#define PROPERTY_SET(type, name) void Set##name(type value) { m_p##name = value; }
#define PROPERTY_GET_SET(type, name) \
	PROPERTY_GET(type, name) \
	PROPERTY_SET(type, name)

template <class entity_type>
class StateMachine
{
private:
	entity_type* m_pOwner;

	State<entity_type>* m_pCurrentState;

	State<entity_type>* m_pPreviousState;

	State<entity_type>* m_pGlobalState;

	bool m_bExetState;

	bool m_bEnterState;


public:
	StateMachine(entity_type* owner)
		: m_pOwner(owner)
		, m_pCurrentState(NULL)
		, m_pPreviousState(NULL)
		, m_pGlobalState(NULL)
		, m_bExetState(false)
		, m_bEnterState(false)
	{}
	virtual ~StateMachine(void) {}

	PROPERTY_SET(State<entity_type>*, CurrentState)

	PROPERTY_SET(State<entity_type>*, GlobalState)

	void Update(float fTime)
	{
		m_pCurrentState->Execute(m_pOwner, fTime);
		m_pGlobalState->Execute(m_pOwner, fTime);
	}

	bool ChangeState(State<entity_type>* pNewState, float fTime)
	{
		_TRACE(_T("ChangeState.\n"));
		assert(m_pCurrentState && pNewState);

		if ( !m_bExetState )
			if ( !( m_bExetState = m_pCurrentState->Exit(m_pOwner, fTime) ) ) return false;
		
		m_pPreviousState = m_pCurrentState;
		m_pCurrentState = pNewState;

		if ( !m_bEnterState )
			if ( !( m_bEnterState = m_pCurrentState->Enter(m_pOwner, fTime) ) ) return false;

		m_bExetState = false;
		m_bEnterState = false;

		return true;
	}

	bool RevertToPreviousState(float fTime)
	{
		_TRACE(_T("RevertToPreviousState.\n"));
		assert(m_pCurrentState && m_pPreviousState);

		if ( !m_bExetState )
			if ( !( m_bExetState = m_pCurrentState->Exit(m_pOwner, fTime) ) ) return false;

		m_pCurrentState = m_pPreviousState;

		if ( !m_bEnterState )
			if ( !( m_bEnterState = m_pCurrentState->Enter(m_pOwner, fTime) ) ) return false;

		m_bExetState = false;
		m_bEnterState = false;

		return true;
	}

};
